DOCHER Mathieu
TP1 - Réggressions linéaires simple et multiple¶
A. Introduction¶
L'objectif de ce TP est de mettre en pratique la méthode de régression linéaire simple et multiple. Pour cela, nous allons utiliser un jeu de données contenant des informations sur le Covid-19 en France.
B. Préparation du jeu de données¶
Dans ce jeu de données, la variable à expliquer les weekly_icu_admissions, qui représente le nombre de personnes admises en soins intensifs chaque semaine.
import pandas as pd
import plotly.express as px
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
from sklearn.linear_model import LinearRegression
import statsmodels.api as sm
import plotly.io as pio
pio.renderers.default = "notebook" # pour ouvrir les graphiques dans le navigateur par défaut
# Récupération des données dans un dataframe
filename = "covidFranceData2022.csv"
df = pd.read_csv(filename)
# Remplacement des données manquantes (NA) par 0 (ici j'ai choisi de supprimer les lignes pour éviter de fausser les résultats, car les valeurs manquantes devrait être en milliers/millions)
df = df.dropna(how="any") # Suppression des lignes avec des valeurs manquantes
# df.fillna(0, inplace=True) # Remplacement des valeurs manquantes par 0
# -> Au final, on ne perd que 6 lignes sur 90.
# # Division du jeu de donnees en deux sous-ensembles (données cumulées et données journalières/hedomadaires)
# df = df[['date','positive_rate','tests_per_case','total_cases','total_deaths','total_tests','total_vaccinations','people_vaccinated','people_fully_vaccinated']]
# df_journalier = df[['date','positive_rate','tests_per_case','new_cases','new_deaths','icu_patients','hosp_patients','weekly_icu_admissions','weekly_hosp_admissions','new_tests','new_vaccinations']]
# # (finalement, je n'ai pas besoin de séparer en deux dataframes comme ça)
df = df.set_index('date')
# print(df.columns) # pour vérifier que la date ne fait pas partie des colonnes
# Visualisations de combinaisons de variables
# Nombre de cas en fonction du nombre de décès
fig = px.scatter(df, x="total_cases", y="total_deaths", color="positive_rate",hover_name=df.index, title="Nombre de décès en fonction du nombre de cas :")
fig.show()
# Nombre de décès hebdomadaires en fonction du nombre de cas hebdomadaires
fig = px.scatter(df, x="new_cases", y="new_deaths", color="positive_rate",hover_name=df.index, title="Nombre de décès en fonction des nouveaux cas :")
fig.show()
# Nombre de personnes en soins intensifs en fonction du nombre total de vaccinés
fig = px.scatter(df, x="people_vaccinated", y="icu_patients", color="positive_rate",hover_name=df.index, title="Nombre de personnes en soins intensifs en fonction du nombre total de vaccinés :")
fig.show()
# Nombre de personnes en soins intensifs par semaine par rapport au nombre de tests par semaine
fig = px.scatter(df, x="new_tests", y="weekly_icu_admissions", color="positive_rate",hover_name=df.index, title="Nombre de personnes en soins intensifs par rapport au nombre de tests par semaine :")
fig.show()
Ces quelques visualisations me semblent pertinentes pour analyser le nombre de personnes admises en soins intensifs et le nombre de décès en fonction du nombre de cas, de la vaccination ou du nombre de tests.
C. Régression linéaire¶
Une régression linéaire consiste à modéliser la relation entre une variable explicative, notée X, et une variable à expliquer, notée Y, par une droite. On utilise la régression linéaire simple lorsque l'on a une seule variable explicative et la régression linéaire multiple dès qu'il y en a plusieurs. La relation entre ces variables est modélisée par l'équation suivante :
$$Y = \beta_0 + \beta_1X_1 + \beta_2X_2 + ... + \beta_nX_n$$
(dans le cas d'une régression linéaire simple, il n'y a que $\beta_0$ et $\beta_1$)
On cherche à estimer les coefficients $\beta$ qui minimisent l'écart entre les valeurs réelles et les valeurs prédites par le modèle.
Pour commencer, on sépare le jeu de données en deux parties : une partie pour l'apprentissage du modèle et une partie pour le test.
df_train, df_test = train_test_split(df,test_size=0.2, random_state=21)
Voici la fonction retournant le modèle de régression linéaire simple :
def regression_lineaire_simple(df, variable_explicative, variable_a_predire):
# Définition de la variable explicative et de la variable à expliquer
X = df[[variable_explicative]]
Y = df[variable_a_predire]
# Modélisation de la régression linéaire avec scikit-learn
model = LinearRegression()
model.fit(X, Y)
# print(f"Variable à expliquer : {variable_a_predire}\nVariable explicative : {variable_explicative}\n\tcoef = {model.coef_[0]:.5f}\n\tintercept = {model.intercept_:.3f}\n\tR2 = {model.score(X, Y):.3f}")
# Modélisation de la régression linéaire avec statsmodels
X2 = sm.add_constant(X)
model_sm = sm.OLS(Y, X2).fit()
print(model_sm.summary())
return model, X
Tout d'abord, nous allons mettre en place une régression linéaire simple avec le nombre d'admissions en hopital comme variable explicative :
model, X = regression_lineaire_simple(df_train, "weekly_hosp_admissions", "weekly_icu_admissions")
# Calcul de l'erreur quadratique moyenne
mse_training = mean_squared_error(df_test["weekly_icu_admissions"], model.predict(df_test[["weekly_hosp_admissions"]]))
print(f"{mse_training=}")
# Affichage du nuage de points et de la droite de régression
fig = px.scatter(df_train, x="weekly_hosp_admissions", y="weekly_icu_admissions", title="Nombre de personnes en soins intensifs par rapport au nombre de personnes hospitalisées :")
fig.add_scatter(x=X['weekly_hosp_admissions'], y=model.predict(X).flatten(), mode='lines', name='Régression linéaire', line=dict(color='limegreen', width=3), hoverinfo='none')
fig.update_layout(width=1000, height=500)
fig.show()
OLS Regression Results
=================================================================================
Dep. Variable: weekly_icu_admissions R-squared: 0.791
Model: OLS Adj. R-squared: 0.788
Method: Least Squares F-statistic: 245.7
Date: Sat, 25 Jan 2025 Prob (F-statistic): 9.20e-24
Time: 14:25:20 Log-Likelihood: -476.33
No. Observations: 67 AIC: 956.7
Df Residuals: 65 BIC: 961.1
Df Model: 1
Covariance Type: nonrobust
==========================================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------------------
const 32.8645 100.543 0.327 0.745 -167.933 233.662
weekly_hosp_admissions 0.1165 0.007 15.673 0.000 0.102 0.131
==============================================================================
Omnibus: 15.820 Durbin-Watson: 1.448
Prob(Omnibus): 0.000 Jarque-Bera (JB): 19.084
Skew: 1.297 Prob(JB): 7.18e-05
Kurtosis: 3.327 Cond. No. 3.70e+04
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 3.7e+04. This might indicate that there are
strong multicollinearity or other numerical problems.
mse_training=83523.14888581011
On fait ensuite la même manipulation avec les variables new deaths et new_tests :
model, X = regression_lineaire_simple(df_train, "new_deaths", "weekly_icu_admissions")
# Calcul de l'erreur quadratique moyenne
mse_training = mean_squared_error(df_test["weekly_icu_admissions"], model.predict(df_test[["new_deaths"]]))
print(f"{mse_training=}")
# Affichage du nuage de points et de la droite de régression
fig = px.scatter(df_train, x="new_deaths", y="weekly_icu_admissions", title="Nombre de personnes en soins intensifs par rapport au nombre de décès :")
fig.add_scatter(x=X['new_deaths'], y=model.predict(X).flatten(), mode='lines', name='Régression linéaire', line=dict(color='limegreen', width=3), hoverinfo='none')
fig.update_layout(width=1000, height=500)
fig.show()
OLS Regression Results
=================================================================================
Dep. Variable: weekly_icu_admissions R-squared: 0.091
Model: OLS Adj. R-squared: 0.077
Method: Least Squares F-statistic: 6.516
Date: Sat, 25 Jan 2025 Prob (F-statistic): 0.0130
Time: 14:25:20 Log-Likelihood: -525.54
No. Observations: 67 AIC: 1055.
Df Residuals: 65 BIC: 1059.
Df Model: 1
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
const 1204.1324 138.842 8.673 0.000 926.845 1481.420
new_deaths 1.5558 0.609 2.553 0.013 0.339 2.773
==============================================================================
Omnibus: 198.584 Durbin-Watson: 1.461
Prob(Omnibus): 0.000 Jarque-Bera (JB): 7.323
Skew: 0.010 Prob(JB): 0.0257
Kurtosis: 1.380 Cond. No. 413.
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
mse_training=232801.57039895718
model, X = regression_lineaire_simple(df_train, "new_tests", "weekly_icu_admissions")
# Calcul de l'erreur quadratique moyenne
mse_training = mean_squared_error(df_test["weekly_icu_admissions"], model.predict(df_test[["new_tests"]]))
print(f"{mse_training=}")
# Affichage du nuage de points et de la droite de régression
fig = px.scatter(df_train, x="new_tests", y="weekly_icu_admissions", title="Nombre de personnes en soins intensifs par rapport au nombre de tests :")
fig.add_scatter(x=X['new_tests'], y=model.predict(X).flatten(), mode='lines', name='Régression linéaire', line=dict(color='limegreen', width=3), hoverinfo='none')
fig.update_layout(width=1000, height=500)
fig.show()
OLS Regression Results
=================================================================================
Dep. Variable: weekly_icu_admissions R-squared: 0.414
Model: OLS Adj. R-squared: 0.405
Method: Least Squares F-statistic: 45.91
Date: Sat, 25 Jan 2025 Prob (F-statistic): 4.31e-09
Time: 14:25:20 Log-Likelihood: -510.84
No. Observations: 67 AIC: 1026.
Df Residuals: 65 BIC: 1030.
Df Model: 1
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
const 974.5104 98.933 9.850 0.000 776.928 1172.092
new_tests 0.0008 0.000 6.776 0.000 0.001 0.001
==============================================================================
Omnibus: 6.171 Durbin-Watson: 1.600
Prob(Omnibus): 0.046 Jarque-Bera (JB): 3.412
Skew: 0.339 Prob(JB): 0.182
Kurtosis: 2.127 Cond. No. 1.38e+06
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 1.38e+06. This might indicate that there are
strong multicollinearity or other numerical problems.
mse_training=147961.73350965846
Il est possible de trouver numériquement les valeurs de $\beta_0$ et $\beta_1$ numériquement :
La pente $\beta_1 = \frac{\sum_{i=1}^{n} (X_i - \bar{X})(Y_i - \bar{Y})}{\sum_{i=1}^{n} (X_i - \bar{X})^2} = \frac{cov(X,Y)}{var(X)}$
Le biais $\beta_0 = \bar{Y} - \beta_1\bar{X}$
X = df_train['new_tests']
Y = df_train['weekly_icu_admissions']
# Calcul de cov(X,Y) et de var(X)
cov_XY = np.cov(X, Y)[0][1]
var_X = np.var(X)
# Calcul du coefficient directeur de la régression linéaire
coef = cov_XY / var_X
# Calcul de l'ordonnée à l'origine de la droite (intercept)
intercept = np.mean(Y) - coef * np.mean(X)
print(f"Les coefficients obtenus par le calcul pour X = 'new tests' sont :\n\t- {coef = :.5f},\n\t- {intercept = :.3f}")
Les coefficients obtenus par le calcul pour X = 'new tests' sont : - coef = 0.00079, - intercept = 966.551
On remarque que les valeurs sont très proches des valeurs obtenues par le modèle de régression linéaire simple de sklearn. La différence vient du fait que sklearn ajuste ses paramètres en entrainant le modèle après avoir calculé les valeurs de $\beta_0$ et $\beta_1$.
Le modèle qui semble être le plus pertinent est celui avec le nombre d'admissions en hopital comme variable explicative. En effet, ses valeurs de R² et de MSE sont respectevement plus élevé et plus faible que les autres modèles. Cela signifie que le modèle est plus précis et que les valeurs prédites sont plus proches des valeurs réelles.
Les variables new deaths et new_tests ne sont pas inutiles, mais elles ne sont pas aussi pertinentes que le nombre d'admissions en hopital. Mais comme nous sommes dans un cas de régression linéaire simple, il ne faut qu'une variable, donc elles sont inutiles ici.
D. Régression linéaire multiple¶
def regression_lineaire_multiple(df, variable_a_predire):
# Définition de la variable explicative et de la variable à expliquer
X = df.drop(variable_a_predire, axis=1)
Y = df[variable_a_predire]
# Modélisation de la régression linéaire avec scikit-learn
model= LinearRegression()
model.fit(X, Y)
# print(f"Variable à expliquer : {variable_a_predire}\n\tcoef = {model.coef_}\n\tintercept = {model.intercept_}\n\tR2 = {model.score(X, Y)}")
# Modélisation de la régression linéaire avec statsmodels
X2 = sm.add_constant(X)
model_sm = sm.OLS(Y, X2).fit()
print(model_sm.summary())
return model, X
model1, X = regression_lineaire_multiple(df_train, "weekly_icu_admissions")
OLS Regression Results
=================================================================================
Dep. Variable: weekly_icu_admissions R-squared: 0.998
Model: OLS Adj. R-squared: 0.997
Method: Least Squares F-statistic: 1400.
Date: Sat, 25 Jan 2025 Prob (F-statistic): 3.51e-61
Time: 14:25:20 Log-Likelihood: -326.97
No. Observations: 67 AIC: 685.9
Df Residuals: 51 BIC: 721.2
Df Model: 15
Covariance Type: nonrobust
===========================================================================================
coef std err t P>|t| [0.025 0.975]
-------------------------------------------------------------------------------------------
const 3.088e+05 8.9e+04 3.468 0.001 1.3e+05 4.88e+05
total_cases 0.0002 0.000 1.284 0.205 -8.84e-05 0.000
new_cases -4.412e-05 8.5e-05 -0.519 0.606 -0.000 0.000
total_deaths -0.2169 0.099 -2.198 0.033 -0.415 -0.019
new_deaths 0.0686 0.058 1.175 0.245 -0.049 0.186
icu_patients 0.6307 0.226 2.792 0.007 0.177 1.084
hosp_patients -0.0851 0.024 -3.527 0.001 -0.134 -0.037
weekly_hosp_admissions 0.1048 0.017 6.182 0.000 0.071 0.139
new_tests -4.6e-05 5e-05 -0.920 0.362 -0.000 5.43e-05
total_tests 0.0001 4.51e-05 2.320 0.024 1.41e-05 0.000
positive_rate -8568.5680 2925.176 -2.929 0.005 -1.44e+04 -2696.032
tests_per_case -275.6044 117.679 -2.342 0.023 -511.854 -39.355
total_vaccinations 7.021e-05 0.000 0.484 0.631 -0.000 0.000
people_vaccinated -0.0059 0.002 -2.542 0.014 -0.011 -0.001
people_fully_vaccinated 0.0001 0.001 0.082 0.935 -0.003 0.003
new_vaccinations 8.899e-05 9.34e-05 0.953 0.345 -9.84e-05 0.000
==============================================================================
Omnibus: 0.787 Durbin-Watson: 2.142
Prob(Omnibus): 0.675 Jarque-Bera (JB): 0.302
Skew: 0.111 Prob(JB): 0.860
Kurtosis: 3.243 Cond. No. 5.69e+12
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 5.69e+12. This might indicate that there are
strong multicollinearity or other numerical problems.
Les variables statistiquement significatives sont celles qui ont un p-value inférieur à 0.05, il y a :
- total_deaths
- icu_patients
- hosp_patients
- weekly_hosp_admissions
- total_tests
- positive_rate
- tests_per_case
- people_vaccinated
On peut donc les utiliser pour faire une régression linéaire multiple et avoir un modèle plus précis.
# On crée un dataframe avec les variables explicatives qui semblent les plus pertinentes
df_train_2 = df_train[['total_deaths','icu_patients','hosp_patients','weekly_hosp_admissions','total_tests','positive_rate','tests_per_case','people_vaccinated','weekly_icu_admissions']]
model2, X = regression_lineaire_multiple(df_train_2, "weekly_icu_admissions")
# Affichage des prédictions
df_test_2 = df_test[['total_deaths','icu_patients','hosp_patients','weekly_hosp_admissions','total_tests','positive_rate','tests_per_case','people_vaccinated','weekly_icu_admissions']]
predictions2 = model2.predict(df_test_2.drop("weekly_icu_admissions", axis=1))
fig = px.scatter(
x=df_test.index,
y=predictions2,
title="Prédictions du nombre de personnes en soins intensifs :",
labels={'x': 'Date', 'y': 'Nombre de personnes en soins intensifs'}
)
fig.add_scatter(
x=df_test.index,
y=predictions2,
mode='markers',
name='Prédictions',
line=dict(color='blue'),
hoverinfo='none'
)
fig.add_scatter(
x=df_test.index,
y=df_test['weekly_icu_admissions'],
mode='markers',
name='Valeurs réelles',
marker=dict(color='red'),
hoverinfo='none'
)
fig.update_layout(width=600, height=500)
fig.show()
OLS Regression Results
=================================================================================
Dep. Variable: weekly_icu_admissions R-squared: 0.997
Model: OLS Adj. R-squared: 0.996
Method: Least Squares F-statistic: 2294.
Date: Sat, 25 Jan 2025 Prob (F-statistic): 1.40e-69
Time: 14:25:20 Log-Likelihood: -335.77
No. Observations: 67 AIC: 689.5
Df Residuals: 58 BIC: 709.4
Df Model: 8
Covariance Type: nonrobust
==========================================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------------------
const 2.125e+05 4.36e+04 4.869 0.000 1.25e+05 3e+05
total_deaths -0.0974 0.080 -1.222 0.227 -0.257 0.062
icu_patients 0.3736 0.195 1.912 0.061 -0.017 0.765
hosp_patients -0.0349 0.013 -2.704 0.009 -0.061 -0.009
weekly_hosp_admissions 0.1228 0.014 8.688 0.000 0.094 0.151
total_tests 9.752e-05 3.02e-05 3.231 0.002 3.71e-05 0.000
positive_rate -9150.0459 1998.305 -4.579 0.000 -1.32e+04 -5150.004
tests_per_case -268.6855 78.132 -3.439 0.001 -425.085 -112.286
people_vaccinated -0.0041 0.001 -5.458 0.000 -0.006 -0.003
==============================================================================
Omnibus: 0.101 Durbin-Watson: 1.932
Prob(Omnibus): 0.951 Jarque-Bera (JB): 0.287
Skew: -0.042 Prob(JB): 0.866
Kurtosis: 2.691 Cond. No. 2.23e+12
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 2.23e+12. This might indicate that there are
strong multicollinearity or other numerical problems.
Etrangement, le modèle où les variables moins pertinentes sont exclues est un peu moins précis (cf la valeur de R², R² ajusté et AIC). c'est peut-être dû à un mauvais tirage aléatoire des données d'entrainement. Ce nouveau modèle semble être un peu meilleur que le précédent malgré tout car il y a deux fois moins de variables pour une précision similaire.
# On crée un dataframe avec les variables explicatives qui semblent les plus pertinentes
df_train_3 = df_train[['positive_rate','tests_per_case','total_cases','total_deaths','total_tests','total_vaccinations','people_vaccinated','people_fully_vaccinated','weekly_icu_admissions']]
model3, X = regression_lineaire_multiple(df_train_3, "weekly_icu_admissions")
# Affichage des prédictions
df_test_3 = df_test[['positive_rate','tests_per_case','total_cases','total_deaths','total_tests','total_vaccinations','people_vaccinated','people_fully_vaccinated','weekly_icu_admissions']]
predictions3 = model3.predict(df_test_3.drop("weekly_icu_admissions", axis=1))
# Pour le fun, prédiction avec toutes les variables (le premier modèle crée dans cette partie)
predictions1 = model1.predict(df_test.drop("weekly_icu_admissions", axis=1))
fig = px.scatter(
x=df_test.index,
y=predictions1,
title="Prédictions du nombre de personnes en soins intensifs :",
labels={'x': 'Date', 'y': 'Nombre de personnes en soins intensifs'}
)
fig.add_scatter(
x=df_test.index,
y=predictions1,
mode='markers',
name='Prédictions (avec toutes les variables)',
line=dict(color='orange'),
hoverinfo='none'
)
fig.add_scatter(
x=df_test.index,
y=predictions2,
mode='markers',
name='Prédictions (avec toutes les variables pertinentes)',
line=dict(color='blue'),
hoverinfo='none'
)
fig.add_scatter(
x=df_test.index,
y=predictions3,
mode='markers',
name='Prédictions (avec uniquement les variables cumulées)',
line=dict(color='green'),
hoverinfo='none'
)
fig.add_scatter(
x=df_test.index,
y=df_test['weekly_icu_admissions'],
mode='markers',
name='Valeurs réelles',
marker=dict(color='red'),
hoverinfo='none'
)
fig.show()
# Calcul de l'erreur quadratique moyenne de chacun des modèles
mse_training1 = mean_squared_error(df_test["weekly_icu_admissions"], predictions1)
print(f"MSE avec toutes les variables:\t{mse_training1:.2f}")
mse_training2 = mean_squared_error(df_test["weekly_icu_admissions"], predictions2)
print(f"MSE avec variables pertinentes:\t{mse_training2:.2f}")
mse_training3 = mean_squared_error(df_test["weekly_icu_admissions"], predictions3)
print(f"MSE avec variables cumulées:\t{mse_training3:.2f}")
OLS Regression Results
=================================================================================
Dep. Variable: weekly_icu_admissions R-squared: 0.993
Model: OLS Adj. R-squared: 0.992
Method: Least Squares F-statistic: 1066.
Date: Sat, 25 Jan 2025 Prob (F-statistic): 5.53e-60
Time: 14:25:20 Log-Likelihood: -361.31
No. Observations: 67 AIC: 740.6
Df Residuals: 58 BIC: 760.5
Df Model: 8
Covariance Type: nonrobust
===========================================================================================
coef std err t P>|t| [0.025 0.975]
-------------------------------------------------------------------------------------------
const 4.05e+05 1.07e+05 3.802 0.000 1.92e+05 6.18e+05
positive_rate -1.75e+04 3276.309 -5.342 0.000 -2.41e+04 -1.09e+04
tests_per_case -654.6979 139.792 -4.683 0.000 -934.522 -374.873
total_cases 0.0001 7.53e-05 1.428 0.159 -4.32e-05 0.000
total_deaths -0.5734 0.033 -17.422 0.000 -0.639 -0.507
total_tests 0.0003 2.52e-05 10.645 0.000 0.000 0.000
total_vaccinations -1.648e-05 0.000 -0.098 0.923 -0.000 0.000
people_vaccinated -0.0064 0.003 -2.402 0.020 -0.012 -0.001
people_fully_vaccinated -0.0007 0.001 -0.512 0.610 -0.004 0.002
==============================================================================
Omnibus: 5.878 Durbin-Watson: 1.932
Prob(Omnibus): 0.053 Jarque-Bera (JB): 5.183
Skew: -0.519 Prob(JB): 0.0749
Kurtosis: 3.883 Cond. No. 4.35e+12
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 4.35e+12. This might indicate that there are
strong multicollinearity or other numerical problems.
MSE avec toutes les variables: 1386.03 MSE avec variables pertinentes: 1999.73 MSE avec variables cumulées: 9340.98
On remarque ici que le modèle de régression linéaire multiple le plus précis est celui utilisant toutes les variables du dataset (son erreur quadratique moyenne (et ses valeurs de R² et R²-ajusté) est plus faible que les autres modèles). Cela signifie que ce modèle est plus précis et que les valeurs prédites sont plus proches des valeurs réelles (comme on peut aussi le voir sur le graphique). Ce modèle est donc le meilleur pour prédire le nombre d'admissions en soins intensifs parmi les modèles testés.
De plus, On peut considérer que le modèle entrainé sur ces données est généralisable car il a été testé sur des données qu'il n'a jamais vues (les échantillons de test) et qu'il a donné des résultats plutôt satisfaisants. Pour être sûr que le modèle est bien généralisable, il faudrait tester le modèle sur un jeu de données plus grand et plus varié.
Extension 1 : Régression polynomiale¶
(comme cette partie n'a pas encore été traitée en cours, j'ai fait ce que j'ai pu à partir de recherches sur internet)
Une régression polynomiale est un cas particulier de régression linéaire où la relation entre les variables est modélisée par un polynôme. On peut donc utiliser une régression polynomiale pour modéliser des relations non-linéaires et anvoir un modèle plus précis.
Le polynôme de régression est de la forme :
$$P_n(x) = a_0 + a_1x + a_2x^2 + ... + a_{n-1}x^{n-1} + a_nx^n$$
Régression polynomiale simple¶
Voici la fonction retournant le modèle de régression polynomiale simple :
from sklearn.preprocessing import PolynomialFeatures
def regression_polynomiale_simple(df, variable_explicative, variable_a_predire, degre):
# Définition de la variable explicative et de la variable à expliquer
X = df[[variable_explicative]]
Y = df[variable_a_predire]
# Modélisation de la régression polynomiale avec scikit-learn
X_poly = PolynomialFeatures(degre).fit_transform(X)
model = LinearRegression()
model.fit(X_poly, Y)
# print(f"Variable à expliquer : {variable_a_predire}\nVariable explicative : {variable_explicative}\n\tcoef = {model.coef_}\n\tintercept = {model.intercept_}\n\tR2 = {model.score(X_poly, Y)}")
# Modélisation de la régression polynomiale avec statsmodels
X2 = sm.add_constant(X_poly)
model_sm = sm.OLS(Y, X2).fit()
# print(model_sm.summary())
return model, X
def add_polynomial_curve(fig, color, degre):
# Création du modèle de régression polynomiale
model, X = regression_polynomiale_simple(df_train, "weekly_hosp_admissions", "weekly_icu_admissions", degre)
# Calcul de l'erreur quadratique moyenne et du R2
mse_training = mean_squared_error(df_test["weekly_icu_admissions"], model.predict(PolynomialFeatures(degre).fit_transform(df_test[["weekly_hosp_admissions"]])))
print(f"{degre=} ->\t{mse_training=:.2f}")
R2 = model.score(PolynomialFeatures(degre).fit_transform(df_test[['weekly_hosp_admissions']]), df_test['weekly_icu_admissions'])
print(f"\t|\t{R2=:.2f}")
# Ajout de la courbe de régression polynomiale
fig.add_scatter(
x=np.sort(X['weekly_hosp_admissions']),
y=model.predict(PolynomialFeatures(degre).fit_transform(np.sort(X[['weekly_hosp_admissions']], axis=0))).flatten(),
mode='lines',
name=f"Régression polynomiale ({degre=})",
line=dict(color=color, width=1),
hoverinfo='none'
)
# Affichage du nuage de points et de la courbe de régression pour les degrés choisis
fig = px.scatter(df_train, x="weekly_hosp_admissions", y="weekly_icu_admissions", title="Nombre de personnes en soins intensifs par rapport au nombre de personnes hospitalisées :")
add_polynomial_curve(fig, 'red', 1)
add_polynomial_curve(fig, 'orange', 2)
add_polynomial_curve(fig, 'green', 5)
add_polynomial_curve(fig, 'purple', 9)
fig.update_layout(width=1000, height=500)
fig.show()
degre=1 -> mse_training=83523.15 | R2=0.67 degre=2 -> mse_training=41477.77 | R2=0.83 degre=5 -> mse_training=34984.57 | R2=0.86 degre=9 -> mse_training=32739.07 | R2=0.87
On remarque ici que le modèle de régression polynomiale simple le plus précis est celui utilisant le polynôme de plus grand degré. En effet, son erreur quadratique moyenne et sa valeur de R² sont plus faibles que les autres modèles. La différence entre le degré 1 et le degré 2 est très importante (division par 2 de la MSE) et plus le degré augmente, moins la précision augmente.
Régression polynomiale multiple¶
def regression_polynomiale_multiple(df, variable_a_predire, degre):
# Définition de la variable explicative et de la variable à expliquer
X = df.drop(variable_a_predire, axis=1)
Y = df[variable_a_predire]
# Modélisation de la régression polynomiale avec scikit-learn
X_poly = PolynomialFeatures(degre).fit_transform(X)
model = LinearRegression()
model.fit(X_poly, Y)
# Modélisation de la régression linéaire avec statsmodels
X2 = sm.add_constant(X)
model_sm = sm.OLS(Y, X2).fit()
print(model_sm.summary())
return model, X
model1, X = regression_polynomiale_multiple(df_train, "weekly_icu_admissions", 2)
# On fait la prédiction sur le jeu de test
df_test_1 = df_test.drop("weekly_icu_admissions", axis=1)
predictions1 = model1.predict(PolynomialFeatures(2).fit_transform(df_test_1))
fig = px.scatter(
x=df_test.index,
y=predictions2,
title="Prédictions du nombre de personnes en soins intensifs :",
labels={'x': 'Date', 'y': 'Nombre de personnes en soins intensifs'}
)
fig.add_scatter(
x=df_test.index,
y=predictions2,
mode='markers',
name='Prédictions',
line=dict(color='blue'),
hoverinfo='none'
)
fig.add_scatter(
x=df_test.index,
y=df_test['weekly_icu_admissions'],
mode='markers',
name='Valeurs réelles',
marker=dict(color='red'),
hoverinfo='none'
)
fig.update_layout(width=600, height=500)
fig.show()
OLS Regression Results
=================================================================================
Dep. Variable: weekly_icu_admissions R-squared: 0.998
Model: OLS Adj. R-squared: 0.997
Method: Least Squares F-statistic: 1400.
Date: Sat, 25 Jan 2025 Prob (F-statistic): 3.51e-61
Time: 14:25:20 Log-Likelihood: -326.97
No. Observations: 67 AIC: 685.9
Df Residuals: 51 BIC: 721.2
Df Model: 15
Covariance Type: nonrobust
===========================================================================================
coef std err t P>|t| [0.025 0.975]
-------------------------------------------------------------------------------------------
const 3.088e+05 8.9e+04 3.468 0.001 1.3e+05 4.88e+05
total_cases 0.0002 0.000 1.284 0.205 -8.84e-05 0.000
new_cases -4.412e-05 8.5e-05 -0.519 0.606 -0.000 0.000
total_deaths -0.2169 0.099 -2.198 0.033 -0.415 -0.019
new_deaths 0.0686 0.058 1.175 0.245 -0.049 0.186
icu_patients 0.6307 0.226 2.792 0.007 0.177 1.084
hosp_patients -0.0851 0.024 -3.527 0.001 -0.134 -0.037
weekly_hosp_admissions 0.1048 0.017 6.182 0.000 0.071 0.139
new_tests -4.6e-05 5e-05 -0.920 0.362 -0.000 5.43e-05
total_tests 0.0001 4.51e-05 2.320 0.024 1.41e-05 0.000
positive_rate -8568.5680 2925.176 -2.929 0.005 -1.44e+04 -2696.032
tests_per_case -275.6044 117.679 -2.342 0.023 -511.854 -39.355
total_vaccinations 7.021e-05 0.000 0.484 0.631 -0.000 0.000
people_vaccinated -0.0059 0.002 -2.542 0.014 -0.011 -0.001
people_fully_vaccinated 0.0001 0.001 0.082 0.935 -0.003 0.003
new_vaccinations 8.899e-05 9.34e-05 0.953 0.345 -9.84e-05 0.000
==============================================================================
Omnibus: 0.787 Durbin-Watson: 2.142
Prob(Omnibus): 0.675 Jarque-Bera (JB): 0.302
Skew: 0.111 Prob(JB): 0.860
Kurtosis: 3.243 Cond. No. 5.69e+12
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 5.69e+12. This might indicate that there are
strong multicollinearity or other numerical problems.
En observant le résultat, on voit que la prédiction obtenue à partie de la régression polynomiale multiple est très proche de celui de la régression linéaire multiple. Cela signifie soit que les deux modèles sont équivalents en terme de précision, soit qu'il y a une erreur dans le code (ce qui est probable 😅).
Conclusion¶
Dans ce TP, nous avons mis en place des modèles de régression linéaire simple et multiple pour prédire le nombre d'admissions en soins intensifs en fonction de différentes variables. Nous avons vu que le modèle le plus précis est celui utilisant toutes les variables du dataset. Nous avons aussi essayé de mettre en place des modèles de régression polynomiale simple et multiple pour voir si un modèle plus précis pouvait être obtenu mais les résultats ne semblent trop proches de ceux des modèles de régression linéaire, c'est étrange...